<HTML>
<HEAD>
<TITLE>JavaScript Source Code 3000:  Games:  Towers of Hanoi</TITLE>
<META HTTP-EQUIV="JavaScript Source Code 3000" CONTENT = "no-cache">
<META NAME="date" CONTENT="2000-09-09">
<META NAME="channel" CONTENT="Web Developer">
<META NAME="author" CONTENT="Adam Stock (adam@digital-biz.com)">
<META NAME="section" CONTENT="Games">
<META NAME="description" CONTENT="See how you do in this wonderful game of skill and logic.  Try to move all the disks onto another pole.  Thing is, you can only move one disk at a time and you must follow size order (a bigger disk can't go on a smaller disk).  Good luck!">
</HEAD>

<BODY BGCOLOR=#ffffff vlink=#0000ff>

<BR>
<center>
<table width=600 cellpadding=0 cellspacing=10>
<tr>
<td width=468 align=center>

    
    
</td>
<td width=120 align=center>
    
</td>
</tr>
</table>
<BR>
<BR>
<basefont size=3>
<FONT SIZE="+2" FACE="Helvetica,Arial">
<A HREF="../index.htm" /" TARGET="_top"><FONT COLOR="#0000FF"><b>Home</b></font></A>
<img src="../img/arrow.gif" /img/arrow.gif" height=13 width=7 border=0 alt="}">
<A HREF="index.htm" /games/"><font color="#FF0000"><b>Games</b></font></A>
<img src="../img/arrow.gif" /img/arrow.gif" height=13 width=7 border=0 alt="}">
<FONT COLOR="#006666"><b>Towers of Hanoi</b></font></font>
<BR>
<BR>
<table BORDER=0 WIDTH=486 CELLPADDING=3 CELLSPACING=0>
<tr><td><font FACE="helvetica,arial,geneva">
<br>
<br>
<!-- Description --><!--content_start-->
See how you do in this wonderful game of skill and logic.  Try to move all the disks onto another pole.  Thing is, you can only move one disk at a time and you must follow size order (a bigger disk can't go on a smaller disk).  Good luck!
<hr>
</td></tr>
</table>
<!-- Demonstration -->
<SCRIPT LANGUAGE="JavaScript">
<!-- Original:  Adam Stock (adam@digital-biz.com) -->

<!-- (c) Copyright 1998-99 Adam L. Stock. All Rights Reserved -->
<!-- You have permission to republish this code provided -->
<!-- that you do not remove this copyright notice -->

<!-- This script and many more are available free online at -->
<!-- The JavaScript Source!! http://javascript.internet.com -->

<!-- Begin

<!-- STEP ONE: STEP TWO: Download this zip file with all the images


   http://javascript.internet.com/img/hanoi/hanoi.zip


// change this to where you upload the images to your site

imgdir = "../img/hanoi/";


function preload() {
this.length = preload.arguments.length;
for (var i = 0; i < this.length; i++) {
this[i] = new Image();
this[i].src = imgdir + preload.arguments[i];
   }
}

var pics = new preload("disk1.gif","disk2.gif",
"disk3.gif","disk4.gif","disk5.gif","disk6.gif",
"disk7.gif","pole.gif", "disk1h.gif","disk2h.gif",
"disk3h.gif","disk4h.gif","disk5h.gif","disk6h.gif",
"disk7h.gif");

var selectedr = null;
var selectedc = null;
var maxposts = 3;
var maxdisks = 7;
var all_posts = 3;
var startpost = 1;
var endpost = (startpost-1 < 0 ? maxposts-1 : startpost-1);
var disks = 7;
var imgwidth = 160;
var imgheight = 14;
var game_is_over = false;
var show_messages = false;
var board = new Array(maxposts);
board[0] = new Array(maxdisks + 1);
board[1] = new Array(maxdisks + 1);
board[2] = new Array(maxdisks + 1);

function initboard(startpost, disks) {
var len = board[0].length;
selectedc = null;
selectedr = null;
game_is_over = false;
endpost = (startpost-1 < 0 ? maxposts-1 : startpost-1);

for (i = 0; i < len; i++) {
board[0][i] = 0;
board[1][i] = 0;
board[2][i] = 0;
}
for (i = len-disks, j = 0; i < len; i++, j++) {
board[startpost][i] = len - j - 1;
   }
}

function drawall() {
for (j=0; j<board.length; j++) {
for (i=0; i<board[j].length; i++) {
draw(j,i, getName( board[j][i]));
   }
}
message("You may begin! Select a piece to move.");
}

function restart(start) {
startpost = start;
disks = document.forms[0].disc.options[document.forms[0].disc.selectedIndex].text;
initboard(startpost,disks);
drawall();
theAnim = new Animation();
}
initboard(startpost, disks);

function getName( num ) {
if (num == 0) return "post.gif";
return "disk" + num + ".gif";
}

function message(str, force) {
if (force || !game_is_over && !show_messages)
document.disp.message.value = str;
}

function messageadd(str) {
if (!game_is_over)
document.disp.message.value = document.disp.message.value + "\n" + str;
}

function isempty(num) {
for (i = 0; i < board[num].length; i++) {
if ( board[num][i] != 0) return false;
}
return true;
}

function topmost(num) {
for (i = 0; i < board[num].length; i++) {
if (board[num][i] != 0) return  i;
}
return -1; 
}

function ispost(i,j) {
return (board[j][i] == 0);
}

function istopdisk(i,j) {
return (board[j][i-1] == 0);
}

function drawboard() {
document.writeln("<h2>The Towers of Hanoi</h2><p>");
document.writeln("<table cellspacing=0 cellpadding=0 border=0>");
document.write("<tr>");
for (j = 0; j < board.length; j++) {
document.write("<td>");
document.write("<a href='javascript:clicked("+0+","+j+")'><img src='" + imgdir + "posttop.gif' border=0></a><br>");
for (i=0; i< board[0].length; i++) {
document.write("<a href='javascript:clicked("+i+","+j+")'>");
document.write("<img src='" + imgdir + getName(board[j][i]) + "' name='pos"+ j + i + "' border=0><br>");
document.write("</a>");
}
document.writeln("</td>");
}
document.write("</tr></table>");
document.write("<form name='disp'><textarea name='message' wrap=virtual rows=2 cols=40></textarea><br>" + 
"Disks: <select name=\"disc\" size=1><option>3<option>4<option>5<option>6<option selected>7</select><input "
+"type=button value=\"Start the Game Over\" onClick=\"restart(startpost);\"><input "
+"type=button value=\"Solve It!\" onClick=\"restart(startpost);setTimeout('hanoi(disks,startpost,endpost)',300)\"></form>");
}

function draw(x,y,name) {
document.images["pos"+x+""+y].src = imgdir + name;
}

function animate(x,y,name) {
theAnim.addFrame( "pos"+x+""+y, imgdir + name);
}

function clicked(i,j) {
document.forms[0].message.focus(); // get rid of annoying outline in MSIE
document.forms[0].message.blur();

if (game_is_over)  restart(startpost = endpost);
if (!isselection() && ispost(i,j)) { message("Select a piece to move."); return; }
if (!ispost(i,j)) { toggle(j); return; };
if (ispost(i,j) && selectedc == j) { message("Move the piece to a different post."); return; }
if (!legalmove(j)) { message("That is not a legal move. Try again."); return; }
move(j); return;
}

function legalmove(j) {
if (isempty(j)) return true;
return (board[j][topmost(j)] < board[selectedc][selectedr]);
}

function isselection() {
return selectedc != null;
}

function toggle( num ) {
var toppos = topmost(num);

if (selectedc == num && selectedr == toppos) {
selectedc = null; selectedr = null;
animate(num,toppos,"disk" + board[num][toppos] + ".gif");
message("Select a piece to move.");
return;
}
if (isselection()) {
animate(selectedc,selectedr,"disk" + board[selectedc][selectedr] + ".gif");
}
selectedc = num; selectedr = toppos;
animate(num,toppos,"disk" + board[num][toppos] + "h.gif");
message("Click on the post to which you want to move the disk.");
}

function move( num ) {
var toppos = (!isempty(num) ? topmost(num) : board[num].length);
board[num][toppos-1] = board[selectedc][selectedr];
board[selectedc][selectedr] = 0;
animate(selectedc,selectedr,"post.gif");
animate(num,toppos-1,"disk" + board[num][toppos-1] + ".gif");
selectedc = null; selectedr = null;
message("Select a piece to move.");
game_over();
}

function hanoi(no_of_disks, start_post, goal_post) {
if (no_of_disks > 0) {
var free_post = all_posts - start_post - goal_post;
hanoi (no_of_disks - 1, start_post, free_post);
show_messages = true;
toggle(start_post);
move(goal_post);
show_messages = false;
hanoi (no_of_disks - 1 , free_post, goal_post);
game_over(true);
   }
}

function game_over(forceMsg) { 
var filledpost = null;
var val = 0;
for (k = 0; k < board.length; k++)  { 
val += ( isempty(k) ? 1 : 0 ); 
if (!isempty(k)) filledpost = k;
}

if (val == 2 && isempty(startpost)) {
message("You won!", forceMsg);
game_is_over = true;
endpost = filledpost;
}
return game_is_over;
}

//
// Animation functions
//

function Animation() {
this.imageNum = new Array();  // Array of indicies document.images to be changed
this.imageSrc = new Array();  // Array of new srcs for imageNum array
this.frameIndex = 0;          // the frame to play next
this.alreadyPlaying = false;  // semaphore to ensure we play smoothly

this.getFrameCount = getframecount;   // the total numebr of frame so far
this.moreFrames = moreframes;         // tells us if there are more frames to play
this.addFrame = addframe;             // add a frame to the animation
this.drawNextFrame = drawnextframe;   // draws the next frame
this.startAnimation = startanimation; // start the animation if necessary
}

function getframecount() {  return this.imageNum.length; }
function moreframes() {  return this.frameIndex < this.getFrameCount(); }
function startanimation() { 
if (!this.alreadyPlaying) {
theAnim.alreadyPlaying = true;
setTimeout('theAnim.drawNextFrame()',5); 
   }
}

function addframe(num, src) {
var theIndex = theAnim.imageNum.length;
theAnim.imageSrc[theIndex] = src;
theAnim.imageNum[theIndex] = num;
theAnim.startAnimation();
}

function drawnextframe() {
if (theAnim.moreFrames()) {
document.images[ theAnim.imageNum[theAnim.frameIndex] ].src = theAnim.imageSrc[theAnim.frameIndex];
theAnim.frameIndex++;
setTimeout('theAnim.drawNextFrame()', 30);
} else {
theAnim.alreadyPlaying = false;
   }
}

drawboard();
var theAnim = new Animation();
message("You may begin! Select a piece to move.");
document.disp.message.value = "";
//  End -->
</script>
<br><br>
You must also upload all these<br>
necessary images to your website.<br>
Download this .zip file and upload<br>
the images to your web server.<br><br>
<a href="../img/hanoi/hanoi.zip" /img/hanoi/hanoi.zip">Dowload hanoi.zip</a><br><br>
<P>
<P>
<a name="source">
<table BORDER=0 WIDTH=486 CELLPADDING=3 CELLSPACING=0>
<tr><td BGCOLOR=yellow><font FACE="helvetica,arial,geneva"><b>JavaScript Source Code 3000:  Games:  Towers of Hanoi</b>
<p>Simply click inside the window below, use your cursor to highlight the script, and copy (type Control-c or Apple-c) the script into a new file in your text editor (such as Note Pad or Simple Text) and save (Control-s or Apple-s).  The script is yours!!!
<br><br></font></td></tr>
<tr><td BGCOLOR=yellow ALIGN=CENTER>
<form NAME="copy">

<DIV align="center">
<input type=button value="Highlight All" onClick="javascript:this.form.txt.focus();this.form.txt.select();">&nbsp;&nbsp;&nbsp;&nbsp;
<INPUT TYPE="text" NAME="total" VALUE="Script Size:  8.91 KB" size=24>
</DIV>

<textarea NAME="txt" ROWS=20 COLS=75 WRAP=VIRTUAL>

&lt;!-- TWO STEPS TO INSTALL TOWERS OF HANOI:

  1.  Copy the coding into the BODY of your HTML document
  2.  Save all the hanoi images to your website directory  --&gt;

&lt;!-- STEP ONE: Paste this code into the BODY of your HTML document  --&gt;

&lt;BODY&gt;

&lt;SCRIPT LANGUAGE="JavaScript"&gt;
&lt;!-- Original:  Adam Stock (adam@digital-biz.com) --&gt;

&lt;!-- (c) Copyright 1998-99 Adam L. Stock. All Rights Reserved --&gt;
&lt;!-- You have permission to republish this code provided --&gt;
&lt;!-- that you do not remove this copyright notice --&gt;

&lt;! &gt;
&lt;! &gt;

&lt;!-- Begin

&lt;!-- STEP TWO: Save these images to your website server directory  --&gt;

//   http://www.yourdomain.com/hanoi-img-directory/disk1.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk1h.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk2.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk2h.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk3.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk3h.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk4.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk4h.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk5.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk5h.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk6.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk6h.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk7.gif
//   http://www.yourdomain.com/hanoi-img-directory/disk7h.gif
//   http://www.yourdomain.com/hanoi-img-directory/post.gif
//   http://www.yourdomain.com/hanoi-img-directory/posttop.gif


// change this to where you upload the images to your site
imgdir = "http://www.your-web-site-address-here.com/images/your-hanoi-image-directory/";


function preload() {
this.length = preload.arguments.length;
for (var i = 0; i &lt; this.length; i++) {
this[i] = new Image();
this[i].src = imgdir + preload.arguments[i];
   }
}

var pics = new preload("disk1.gif","disk2.gif",
"disk3.gif","disk4.gif","disk5.gif","disk6.gif",
"disk7.gif","pole.gif", "disk1h.gif","disk2h.gif",
"disk3h.gif","disk4h.gif","disk5h.gif","disk6h.gif",
"disk7h.gif");

var selectedr = null;
var selectedc = null;
var maxposts = 3;
var maxdisks = 7;
var all_posts = 3;
var startpost = 1;
var endpost = (startpost-1 &lt; 0 ? maxposts-1 : startpost-1);
var disks = 7;
var imgwidth = 160;
var imgheight = 14;
var game_is_over = false;
var show_messages = false;
var board = new Array(maxposts);
board[0] = new Array(maxdisks + 1);
board[1] = new Array(maxdisks + 1);
board[2] = new Array(maxdisks + 1);

function initboard(startpost, disks) {
var len = board[0].length;
selectedc = null;
selectedr = null;
game_is_over = false;
endpost = (startpost-1 &lt; 0 ? maxposts-1 : startpost-1);

for (i = 0; i &lt; len; i++) {
board[0][i] = 0;
board[1][i] = 0;
board[2][i] = 0;
}
for (i = len-disks, j = 0; i &lt; len; i++, j++) {
board[startpost][i] = len - j - 1;
   }
}

function drawall() {
for (j=0; j&lt;board.length; j++) {
for (i=0; i&lt;board[j].length; i++) {
draw(j,i, getName( board[j][i]));
   }
}
message("You may begin! Select a piece to move.");
}

function restart(start) {
startpost = start;
disks = document.forms[0].disc.options[document.forms[0].disc.selectedIndex].text;
initboard(startpost,disks);
drawall();
theAnim = new Animation();
}
initboard(startpost, disks);

function getName( num ) {
if (num == 0) return "post.gif";
return "disk" + num + ".gif";
}

function message(str, force) {
if (force || !game_is_over && !show_messages)
document.disp.message.value = str;
}

function messageadd(str) {
if (!game_is_over)
document.disp.message.value = document.disp.message.value + "\n" + str;
}

function isempty(num) {
for (i = 0; i &lt; board[num].length; i++) {
if ( board[num][i] != 0) return false;
}
return true;
}

function topmost(num) {
for (i = 0; i &lt; board[num].length; i++) {
if (board[num][i] != 0) return  i;
}
return -1; 
}

function ispost(i,j) {
return (board[j][i] == 0);
}

function istopdisk(i,j) {
return (board[j][i-1] == 0);
}

function drawboard() {
document.writeln("&lt;h2&gt;The Towers of Hanoi&lt;/h2&gt;&lt;p&gt;");
document.writeln("&lt;table cellspacing=0 cellpadding=0 border=0&gt;");
document.write("&lt;tr&gt;");
for (j = 0; j &lt; board.length; j++) {
document.write("&lt;td&gt;");
document.write("&lt;a href='javascript:clicked("+0+","+j+")'&gt;&lt;img src='" + imgdir + "posttop.gif' border=0&gt;&lt;/a&gt;&lt;br&gt;");
for (i=0; i&lt; board[0].length; i++) {
document.write("&lt;a href='javascript:clicked("+i+","+j+")'&gt;");
document.write("&lt;img src='" + imgdir + getName(board[j][i]) + "' name='pos"+ j + i + "' border=0&gt;&lt;br&gt;");
document.write("&lt;/a&gt;");
}
document.writeln("&lt;/td&gt;");
}
document.write("&lt;/tr&gt;&lt;/table&gt;");
document.write("&lt;form name='disp'&gt;&lt;textarea name='message' wrap=virtual rows=2 cols=40&gt;&lt;/textarea&gt;&lt;br&gt;" + 
"Disks: &lt;select name=\"disc\" size=1&gt;&lt;option&gt;3&lt;option&gt;4&lt;option&gt;5&lt;option&gt;6&lt;option selected&gt;7&lt;/select&gt;&lt;input "
+"type=button value=\"Start the Game Over\" onClick=\"restart(startpost);\"&gt;&lt;input "
+"type=button value=\"Solve It!\" onClick=\"restart(startpost);setTimeout('hanoi(disks,startpost,endpost)',300)\"&gt;&lt;/form&gt;");
}

function draw(x,y,name) {
document.images["pos"+x+""+y].src = imgdir + name;
}

function animate(x,y,name) {
theAnim.addFrame( "pos"+x+""+y, imgdir + name);
}

function clicked(i,j) {
document.forms[0].message.focus(); // get rid of annoying outline in MSIE
document.forms[0].message.blur();

if (game_is_over)  restart(startpost = endpost);
if (!isselection() && ispost(i,j)) { message("Select a piece to move."); return; }
if (!ispost(i,j)) { toggle(j); return; };
if (ispost(i,j) && selectedc == j) { message("Move the piece to a different post."); return; }
if (!legalmove(j)) { message("That is not a legal move. Try again."); return; }
move(j); return;
}

function legalmove(j) {
if (isempty(j)) return true;
return (board[j][topmost(j)] &lt; board[selectedc][selectedr]);
}

function isselection() {
return selectedc != null;
}

function toggle( num ) {
var toppos = topmost(num);

if (selectedc == num && selectedr == toppos) {
selectedc = null; selectedr = null;
animate(num,toppos,"disk" + board[num][toppos] + ".gif");
message("Select a piece to move.");
return;
}
if (isselection()) {
animate(selectedc,selectedr,"disk" + board[selectedc][selectedr] + ".gif");
}
selectedc = num; selectedr = toppos;
animate(num,toppos,"disk" + board[num][toppos] + "h.gif");
message("Click on the post to which you want to move the disk.");
}

function move( num ) {
var toppos = (!isempty(num) ? topmost(num) : board[num].length);
board[num][toppos-1] = board[selectedc][selectedr];
board[selectedc][selectedr] = 0;
animate(selectedc,selectedr,"post.gif");
animate(num,toppos-1,"disk" + board[num][toppos-1] + ".gif");
selectedc = null; selectedr = null;
message("Select a piece to move.");
game_over();
}

function hanoi(no_of_disks, start_post, goal_post) {
if (no_of_disks &gt; 0) {
var free_post = all_posts - start_post - goal_post;
hanoi (no_of_disks - 1, start_post, free_post);
show_messages = true;
toggle(start_post);
move(goal_post);
show_messages = false;
hanoi (no_of_disks - 1 , free_post, goal_post);
game_over(true);
   }
}

function game_over(forceMsg) { 
var filledpost = null;
var val = 0;
for (k = 0; k &lt; board.length; k++)  { 
val += ( isempty(k) ? 1 : 0 ); 
if (!isempty(k)) filledpost = k;
}

if (val == 2 && isempty(startpost)) {
message("You won!", forceMsg);
game_is_over = true;
endpost = filledpost;
}
return game_is_over;
}

//
// Animation functions
//

function Animation() {
this.imageNum = new Array();  // Array of indicies document.images to be changed
this.imageSrc = new Array();  // Array of new srcs for imageNum array
this.frameIndex = 0;          // the frame to play next
this.alreadyPlaying = false;  // semaphore to ensure we play smoothly

this.getFrameCount = getframecount;   // the total numebr of frame so far
this.moreFrames = moreframes;         // tells us if there are more frames to play
this.addFrame = addframe;             // add a frame to the animation
this.drawNextFrame = drawnextframe;   // draws the next frame
this.startAnimation = startanimation; // start the animation if necessary
}

function getframecount() {  return this.imageNum.length; }
function moreframes() {  return this.frameIndex &lt; this.getFrameCount(); }
function startanimation() { 
if (!this.alreadyPlaying) {
theAnim.alreadyPlaying = true;
setTimeout('theAnim.drawNextFrame()',5); 
   }
}

function addframe(num, src) {
var theIndex = theAnim.imageNum.length;
theAnim.imageSrc[theIndex] = src;
theAnim.imageNum[theIndex] = num;
theAnim.startAnimation();
}

function drawnextframe() {
if (theAnim.moreFrames()) {
document.images[ theAnim.imageNum[theAnim.frameIndex] ].src = theAnim.imageSrc[theAnim.frameIndex];
theAnim.frameIndex++;
setTimeout('theAnim.drawNextFrame()', 30);
} else {
theAnim.alreadyPlaying = false;
   }
}

drawboard();
var theAnim = new Animation();
message("You may begin! Select a piece to move.");
document.disp.message.value = "";
//  End --&gt;
&lt;/script&gt;

 

&lt;!-- Script Size:  8.91 KB --&gt;</textarea><br><font FACE="helvetica,arial,geneva"></font></td></tr>

</table>
</form>
</FONT>
</CENTER>


</center>
</body></html>